package br.org.bertol.mestrado;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

import org.apache.log4j.Logger;

import br.org.bertol.mestrado.engine.Objective;

/**
 * @author contaqualquer
 */
public class Verify {

    /**
     * Conjunto de restrições fortes.
     */
    private transient List<List<Integer>> strongConstraint;

    /**
     * Conjunto de classes.
     */
    private transient ArrayList<Integer>  classes;

    /***/
    private transient boolean             systemEnable = false;

    /**
     * Lista de Objetivos.
     */
    private final transient Objective[]   objectives;

    public Verify(final Objective[] objectives, final String source,
        final String... sistemas) {

        strongConstraint = new ArrayList<List<Integer>>();

        classes = new ArrayList<Integer>();

        this.objectives = objectives;

        try {

            uploadSystem(source, sistemas);

            // instancia classes
            discoverClasses(strongConstraint.size());

        } catch (IOException e) {
            e.printStackTrace();
            System.exit(1);
        }
    }

    private void uploadSystem(final String source, final String... sistemas)
            throws IOException {
        systemEnable = true;

        for (String sistema : sistemas) {
            strongConstraint = Objective.loadStrongConstraint(source, sistema);

            // para cada sistema verifica se a matrix de preced�ncia foi
            // carregada
            if (strongConstraint.size() == 0) {
                Logger
                        .getLogger(this.getClass())
                        .error(
                               "Sistema "
                        + sistema
                        + " deve ter a matrix de precedência definida.");
                systemEnable = false;
                break;
            } else {
                for (Objective objective : objectives) {

                    objective.loadParameters(source, sistema);

                    if (objective.getWeekConstraint().size() == 0) {
                        Logger.getLogger(this.getClass())
                                .error(
                                       "Sistema " + sistema
                                + " deve ter a matrix de "
                                + objectives.toString()
                                + " definida.");
                        systemEnable = false;
                        break;
                    }

                }
            }
        }
    }

    /**
     * Monta uma lista com todas as classes dos sistema e as classes iniciais.
     * @param numClasses
     *            Total de classes do sistema
     * @return Array com todas as classes disponíveis
     */
    private ArrayList<Integer> discoverClasses(final int numClasses) {

        // instancias as classes do problema
        for (int i = 0; i < numClasses; i++) {
            classes.add(i + 1);
        }

        return classes;
    }

    /**
     * @return {@link List} Retorna todas as classes possiveis de começar um
     *         caminho.
     */
    public final List<Integer> getStartClasses() {

        final ArrayList<Integer> startClasses = new ArrayList<Integer>();

        for (Integer classe : classes) {

            if (strongConstraint.get(classe - 1).size() == 1) {
                startClasses.add(classe.intValue());
            }
        }

        return startClasses;
    }

    /**
     * @return the classes
     */
    @SuppressWarnings("unchecked")
    public final List<Integer> getClasses() {
        return (ArrayList<Integer>) classes.clone();
    }

    /**
     * @return the height
     */
    public final Objective[] getObjectives() {
        return objectives;
    }

    /**
     * @return the systemEnable
     */
    public final boolean isSystemEnable() {
        return systemEnable;
    }

    /**
     * @return the strongConstraint
     */
    public List<List<Integer>> getStrongConstraint() {
        return strongConstraint;
    }
}
